package com.cwt.framework.permission;

import cn.dev33.satoken.context.second.SaTokenSecondContext;
import cn.dev33.satoken.stp.StpInterface;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaTokenConsts;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cwt.common.constant.SaTokenConst;
import com.cwt.common.utils.CollectionUtils;
import com.cwt.service.domain.SysMenu;
import com.cwt.service.domain.SysRole;
import com.cwt.service.service.SysMenuService;
import com.cwt.service.service.SysRoleService;
import com.cwt.service.service.SysUserRoleService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author chenwt
 * @version V1.0
 * @describe 【自定义权限加载接口实现类】
 * 有同学会产生疑问：我实现了此接口，但是程序启动时好像并没有执行，是不是我写错了？
 * 答：不执行是正常现象，程序启动时不会执行这个接口的方法，在每次调用鉴权代码时，才会执行到此。
 * @date 2023年07月17日 14:50:55
 */
@Component // 保证此类被 SpringBoot 扫描，完成 Sa-Token 的自定义权限验证扩展
public class StpInterfaceImpl implements StpInterface {

    private static final Logger logger = LoggerFactory.getLogger(StpInterfaceImpl.class);

    @Autowired
    private SysMenuService sysMenuService;

    @Autowired
    private SysRoleService sysRoleService;

    /**
     * 返回一个账号所拥有的权限码集合
     *
     * @param loginId   登录id
     * @param loginType 账号体系标识
     * @return 权限集合
     */
    @Override
    public List<String> getPermissionList(Object loginId, String loginType) {
        logger.info("账号所拥有的权限码集合");

        // 从session中获取
        Object object = StpUtil.getTokenSession().get(SaTokenConst.PERMISSION_LIST);
        if (!ObjectUtils.isEmpty(object)) {
            return (List<String>) object;
        }

        // 超级管理员
        if (StpUtil.hasRole(SaTokenConst.MANAGE_USER)) {
            return Collections.singletonList("*");
        }

        // 本 list 仅做模拟，实际项目中要根据具体业务逻辑来查询权限
        List<String> permissions = sysMenuService.getMenuPermission(Long.valueOf((String) loginId))
                .stream().map(SysMenu::getCode).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(permissions)) {
            StpUtil.getTokenSession().set(SaTokenConst.PERMISSION_LIST, permissions);
        }
        return permissions;
    }

    /**
     * 返回一个账号所拥有的角色标识集合 (权限与角色可分开校验)
     *
     * @param loginId   登录id
     * @param loginType 账号体系标识
     * @return 角色标识集合
     */
    @Override
    public List<String> getRoleList(Object loginId, String loginType) {
        logger.info("账号所拥有的角色标识集合");

        // 从session中获取
        Object object = StpUtil.getTokenSession().get(SaTokenConst.ROLE_LIST);
        if (!ObjectUtils.isEmpty(object)) {
            return (List<String>) object;
        }

        // 本 list 仅做模拟，实际项目中要根据具体业务逻辑来查询角色
        List<String> roles = sysRoleService.getUserRoles(Long.valueOf((String) loginId))
                .stream().map(SysRole::getCode).collect(Collectors.toList());

        // 存入session中
        if (CollectionUtil.isNotEmpty(roles)) {
            StpUtil.getTokenSession().set(SaTokenConst.ROLE_LIST, roles);
        }
        return roles;
    }

}
